package com.idc.common.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

public class RadixUtil {

	private static final String DEFAULT_RADIXS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

	private static char[] DEFAULT_ARR = DEFAULT_RADIXS.toCharArray();

	private static int DEFAULT_NUM = DEFAULT_RADIXS.length();

	private static Map<Character, Integer> DEFAULT_MAP = new ConcurrentHashMap<>();

	static {
		for (int i = 0; i < DEFAULT_ARR.length; i++) {
			DEFAULT_MAP.put(DEFAULT_ARR[i], i);
		}
	}

	public static String encode(long n) {
		StringBuilder sb = new StringBuilder();
		for (;;) {
			long left = n % DEFAULT_NUM;
			sb.append(DEFAULT_ARR[(int) left]);
			if (n < DEFAULT_NUM) {
				break;
			}
			n = n / DEFAULT_NUM;
		}
		return sb.reverse().toString();
	}
	
	public static String encode(String radixs, long n) {
		char[] arr = radixs.toCharArray();
		int num = radixs.length();
		StringBuilder sb = new StringBuilder();
		for (;;) {
			long left = n % num;
			sb.append(arr[(int) left]);
			if (n < num) {
				break;
			}
			n = n / num;
		}
		return sb.reverse().toString();
	}

	public static String encode(String n) {
		BigDecimal bigDecimal = new BigDecimal(n);
		StringBuilder sb = new StringBuilder();
		for (;;) {
			// long left = n % num;
			BigDecimal left = bigDecimal.remainder(new BigDecimal(DEFAULT_NUM));
			sb.append(DEFAULT_ARR[left.intValue()]);
			if (bigDecimal.compareTo(new BigDecimal(DEFAULT_NUM)) < 0) {
				break;
			}
			bigDecimal = bigDecimal.divide(new BigDecimal(DEFAULT_NUM), 1);
		}
		return sb.reverse().toString();
	}

	public static String encode(String radixs, String n) {
		char[] arr = radixs.toCharArray();
		int num = radixs.length();
		BigDecimal bigDecimal = new BigDecimal(n);
		StringBuilder sb = new StringBuilder();
		for (;;) {
			BigDecimal left = bigDecimal.remainder(new BigDecimal(num));
			sb.append(arr[left.intValue()]);
			if (bigDecimal.compareTo(new BigDecimal(num)) < 0) {
				break;
			}
			bigDecimal = bigDecimal.divide(new BigDecimal(num), 1);
		}
		return sb.reverse().toString();
	}

	public static long decode(String n) {
		long total = 0;
		for (int i = 0; i < n.length(); i++) {
			char c = n.charAt(i);
			total = total * DEFAULT_NUM + DEFAULT_MAP.get(c);
		}
		return total;
	}

	public static long decode(String radixs, String n) {
		char[] arr = radixs.toCharArray();
		int num = radixs.length();
		Map<Character, Integer> map = new ConcurrentHashMap<>();
		for (int i = 0; i < arr.length; i++) {
			map.put(arr[i], i);
		}
		long total = 0;
		for (int i = 0; i < n.length(); i++) {
			char c = n.charAt(i);
			total = total * num + map.get(c);
		}
		return total;
	}

	public static BigDecimal decodeToBigDecimal(String n) {
		BigDecimal total = new BigDecimal(0);
		for (int i = 0; i < n.length(); i++) {
			char c = n.charAt(i);
			total = total.multiply(new BigDecimal(DEFAULT_NUM)).add(new BigDecimal(DEFAULT_MAP.get(c)));
		}
		return total;
	}

	public static BigDecimal decodeToBigDecimal(String radixs, String n) {
		char[] arr = radixs.toCharArray();
		int num = radixs.length();
		Map<Character, Integer> map = new ConcurrentHashMap<>();
		for (int i = 0; i < arr.length; i++) {
			map.put(arr[i], i);
		}
		BigDecimal total = new BigDecimal(0);
		for (int i = 0; i < n.length(); i++) {
			char c = n.charAt(i);
			total = total.multiply(new BigDecimal(num)).add(new BigDecimal(map.get(c)));
		}
		return total;
	}

	public static String genRadixs() {
		List<Character> characters = new ArrayList<>();
		StringBuilder results = new StringBuilder();
		for (int i = 0; i < DEFAULT_NUM; i++) {
			characters.add(DEFAULT_ARR[i]);
		}
		Random random = new Random();
		int n = characters.size();
		for (int i = 0; i < n; i++) {
			int a = random.nextInt(characters.size());
			results.append(characters.get(a));
			characters.remove(a);
		}
		return StringUtils.join(results);
	}

}
